﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using System.Text;
using System.Threading;
using Microsoft.SharePoint.Client;

namespace SharePointOnlineCmdlets
{
    /// <summary>
    /// Creates a new SharePoint Online Web.
    /// </summary>
    [Cmdlet(VerbsCommon.New, "SPOWeb")]
    public class NewSPOWeb : PSCmdlet
    {
        [Parameter(Mandatory = true, ValueFromPipeline = true)]
        public Web Web { get; set; }

        [Parameter(Mandatory = true)]
        public string Title { get; set; }

        [Parameter]
        public string Description { get; set; }

        [Parameter(Mandatory = true)]
        public string WebTemplate { get; set; }

        [Parameter(Mandatory = true)]
        public string Url { get; set; }

        protected override void ProcessRecord()
        {
            var Context = Web.Context;
            var webs = Web.Webs;
            Context.Load(webs);
            Context.ExecuteQuery();
            var newWeb = webs.Add(new WebCreationInformation()
            {
                Description = Description,
                Language = 1033,
                Title = Title,
                Url = Url,
                UseSamePermissionsAsParentSite = true,
                WebTemplate = WebTemplate
            });
            Web.Context.Load(newWeb, w => w.Title, x => x.ServerRelativeUrl);
            Context.ExecuteQuery();
            WriteObject(newWeb);
        }
    }

    /// <summary>
    /// Gets an SPOWeb 
    /// </summary>
    [Cmdlet(VerbsCommon.Get, "SPOWeb")]
    public class GetSPOWeb : PSCmdlet
    {
        [Parameter(Mandatory = true, ValueFromPipeline = true)]
        public Web Web { get; set; }

        [Parameter(Mandatory = true)]
        public string WebUrl { get; set; }

        protected override void ProcessRecord()
        {
            try
            {
                ClientContext ctx = (ClientContext)Web.Context;
                ctx.Load(Web, p => p.Webs);
                ctx.ExecuteQuery();
                var web = Web.Webs.FirstOrDefault(w => w.Url.Split('/').Last().ToLower() == WebUrl.ToLower());
                ctx.Load(web);
                ctx.ExecuteQuery();
                WriteObject(web);
            }catch(Exception e)
            {
                WriteObject(null);
            }
        }
    }

    /// <summary>
    /// Gets all subwebs of a web 
    /// </summary>
    [Cmdlet(VerbsCommon.Get, "SPOSubWebs")]
    public class GetSPOSubWebs : PSCmdlet
    {
        [Parameter(Mandatory = true, ValueFromPipeline = true)]
        public Web Web { get; set; }

        protected override void ProcessRecord()
        {
            ClientContext ctx = (ClientContext)Web.Context;
            ctx.Load(Web, p => p.Webs.IncludeWithDefaultProperties(w=> w.Title, x => x.ServerRelativeUrl));
            ctx.ExecuteQuery();
            WriteObject(Web.Webs);
        }
    }

    /// <summary>
    /// Gets all features activated on a Web
    /// </summary>
    [Cmdlet(VerbsCommon.Get, "SPOWebFeatures")]
    public class GetSPOWebFeatures : PSCmdlet
    {
        [Parameter(Mandatory = true, ValueFromPipeline = true)]
        public Web Web { get; set; }

        protected override void ProcessRecord()
        {
            var ctx = (ClientContext)Web.Context;
            ctx.Load(Web, p => p.Features);
            ctx.ExecuteQuery();
            WriteObject(Web.Features);
        }
    }

    /// <summary>
    /// Removes a specific subweb
    /// </summary>
    [Cmdlet(VerbsCommon.Remove, "SPOWeb")]
    public class RemoveSPOWeb : PSCmdlet
    {
        [Parameter(Mandatory = true, ValueFromPipeline = true)]
        public Web Web { get; set; }

        protected override void ProcessRecord()
        {
            Web.DeleteObject();
            Web.Context.ExecuteQuery();
        }
    }

    /// <summary>
    /// Apply a web template to a web
    /// </summary>
    [Cmdlet(VerbsCommon.Set, "SPOWebTemplate")]
    public class SetSPOWebTemplate : Cmdlet
    {
        [Parameter(Mandatory = true, ValueFromPipeline = true)]
        public Web Web { get; set; }

        [Parameter(Mandatory = true)]
        public string TemplateId { get; set; }

        protected override void ProcessRecord()
        {
            try
            {
                Web.Context.RequestTimeout = 6000000;
                Web.ApplyWebTemplate(TemplateId);
                Web.Update();
                Web.Context.Load(Web, w => w.Title, x => x.ServerRelativeUrl);
                Web.Context.ExecuteQuery();
            }
            catch (ServerException ex)
            {
                if (!ex.Message.Contains("The operation has timed out.")) throw;
                Web.Context.Load(Web, w => w.Title, x => x.ServerRelativeUrl);
                Web.Context.ExecuteQuery();
            }
            WriteObject(Web);
        }
    }

    /// <summary>
    /// Get available web templates for a web
    /// </summary>
    [Cmdlet(VerbsCommon.Get, "SPOWebTemplates")]
    public class GetSPOWebTemplates : Cmdlet
    {
        [Parameter(Mandatory = true, ValueFromPipeline = true)]
        public Web Web { get; set; }

        protected override void ProcessRecord()
        {
            var templates = Web.GetAvailableWebTemplates(1033, true);
            Web.Context.Load(templates);
            Web.Context.ExecuteQuery();
            WriteObject(templates);
        }
    }

    /// <summary>
    /// Sets the master page url for a web
    /// </summary>
    [Cmdlet(VerbsCommon.Set, "SPOMasterPage")]
    public class SetSPOMasterPage : PSCmdlet
    {
        [Parameter(Mandatory = true, ValueFromPipeline = true)]
        public Web Web { get; set; }

        [Parameter(Mandatory = true)]
        public string Url { get; set; }

        [Parameter]
        public SwitchParameter System { get; set; }

        [Parameter]
        public SwitchParameter Both { get; set; }

        protected override void ProcessRecord()
        {
            var ctx = (ClientContext) Web.Context;
            ctx.Load(ctx.Site, site => site.ServerRelativeUrl);
            ctx.ExecuteQuery();
            var masterUrl = ctx.Site.ServerRelativeUrl.TrimEnd('/') + "/" + Url.TrimStart('/');
            if (System.IsPresent)
            {
                Web.MasterUrl = masterUrl;
            }
            else
            {
                if (Both.IsPresent) Web.MasterUrl = masterUrl;
                Web.CustomMasterUrl = masterUrl;
            }
            Web.Update();
            ctx.Load(Web, w => w.Title, x => x.ServerRelativeUrl);
            ctx.ExecuteQuery();
            WriteObject(Web);
        }
    }

    /// <summary>
    /// Sets the theme for a web
    /// </summary>
    [Cmdlet(VerbsCommon.Set, "SPOTheme")]
    public class SetSPOTheme : PSCmdlet
    {
        [Parameter(Mandatory = true, ValueFromPipeline = true)]
        public Web Web { get; set; }

        [Parameter(Mandatory = true)]
        public string ColorUrl { get; set; }

        [Parameter]
        public string FontUrl { get; set; }

        [Parameter]
        public string BackgroundUrl { get; set; }

        [Parameter]
        public bool StoreRoot { get; set; }

        protected override void ProcessRecord()
        {
            var ctx = (ClientContext)Web.Context;
            ctx.Load(ctx.Site, site => site.ServerRelativeUrl);
            ctx.ExecuteQuery();
            ColorUrl = ctx.Site.ServerRelativeUrl.TrimEnd('/') + '/' + ColorUrl.TrimStart('/');
            if (FontUrl != null)
                FontUrl = ctx.Site.ServerRelativeUrl.TrimEnd('/') + '/' + FontUrl.TrimStart('/');
            if(BackgroundUrl!=null)
                BackgroundUrl = ctx.Site.ServerRelativeUrl.TrimEnd('/') + '/' + BackgroundUrl.TrimStart('/');
            Web.ApplyTheme(ColorUrl,FontUrl,BackgroundUrl,StoreRoot);
            Web.Update();
            Web.Context.ExecuteQuery();
            WriteObject(Web);
        }
    }
}
